package com.qiwenshare.stock.strategy;

import cn.hutool.core.date.DateUtil;
import com.qiwenshare.stock.domain.StockDayInfo;
import com.qiwenshare.stock.domain.StockInfo;
import com.qiwenshare.stock.service.StockDayInfoService;
import com.qiwenshare.stock.service.StockService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Calendar;
import java.util.List;

/**
 * @ClassName RangeBreak
 * @Description TODO
 * @Author peng.zhang
 * @Date 16:28 2023/6/9
 * @Version 1.0
 **/
@Slf4j
@Component
public class RangeBreakStrategy {
    @Resource
    private StockService stockService;
    @Resource
    private StockDayInfoService stockDayInfoService;

    /**
     * 向上突破
     *
     * @param todayInfo
     * @param preDayInfo
     * @return
     */
    public static double rangeUpBreakByNum(StockDayInfo todayInfo, StockDayInfo preDayInfo) {
        //区间计算
        //(1)N日High的最高价HH,N日Close的最低价LC;
        //(2)N日Close的最高价HC,N日Low的最低价LL;
        //(3)Range = Max(HH-LC,HC-LL)
        //(4)上轨BuyLine = Open + K1×Range
        //(5)下轨SellLine = Open - K2×Range。
        //通常情况下，N的取值范围位于0.5-0.8之间。
        double n = 0.5;
        try {
            if (preDayInfo != null && todayInfo != null) {
                double range = preDayInfo.getHigh() - preDayInfo.getLow();
                double highLine = todayInfo.getOpen() + n * range;
                double lowLine = todayInfo.getOpen() - n * range;
                //当前价格突破区间上线,并且今日未突破过区间下限
                if (todayInfo.getHigh() > highLine && todayInfo.getLow() > lowLine) {
                    return highLine;
                }
            }
        } catch (Exception e) {
        }
        return 0;
    }

    /**
     * 向下突破
     *
     * @param todayInfo
     * @param preDayInfo
     * @return
     */
    public static double rangeDownBreakByNum(StockDayInfo todayInfo, StockDayInfo preDayInfo) {
        //区间计算
        //(1)N日High的最高价HH,N日Close的最低价LC;
        //(2)N日Close的最高价HC,N日Low的最低价LL;
        //(3)Range = Max(HH-LC,HC-LL)
        //(4)上轨BuyLine = Open + K1×Range
        //(5)下轨SellLine = Open - K2×Range。
        //通常情况下，N的取值范围位于0.5-0.8之间。
        double n = 0.5;
        try {
            if (preDayInfo != null && todayInfo != null) {
                double range = preDayInfo.getHigh() - preDayInfo.getLow();
                double highLine = todayInfo.getOpen() + n * range;
                double lowLine = todayInfo.getOpen() - n * range;
                //当前价格突破区间上线,并且今日未突破过区间下限
                if (todayInfo.getLow() < lowLine) {
                    return lowLine;
                }
            }
        } catch (Exception e) {
        }
        return 0;
    }

    public void backTest(String start, String end) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(DateUtil.parseDate(start));
        calendar.add(Calendar.DAY_OF_YEAR,1);
        String tomorrow = DateUtil.format(calendar.getTime(), "YYYY-MM-dd");
        List<StockInfo> list = stockService.list();
        int successCount = 0;
        int failCount = 0;
        for (StockInfo s : list) {
            List<StockDayInfo> threeDayInfo = stockDayInfoService.list3DayInfo(s.getStockNum(),tomorrow);
            if(threeDayInfo==null||threeDayInfo.size()<3){
                continue;
            }
            StockDayInfo yesterdayInfo = threeDayInfo.get(2);
            StockDayInfo todayInfo = threeDayInfo.get(1);
            StockDayInfo tomorrowInfo =threeDayInfo.get(0);
            double breakPrice = rangeDownBreakByNum(todayInfo, yesterdayInfo);
//            double breakPrice = rangeUpBreakByNum(todayInfo, yesterdayInfo);
            if (breakPrice > 0) {
                log.info("stockNum:{},stockName:{},buy price:{},open:{},high:{},low:{},ratio:{},get:{}",
                        tomorrowInfo.getStockNum(),
                        tomorrowInfo.getStockName(),
                        breakPrice,
                        tomorrowInfo.getOpen(),
                        tomorrowInfo.getHigh(),
                        tomorrowInfo.getLow(),
                        tomorrowInfo.getChangeRatio(),
                        (tomorrowInfo.getOpen()-breakPrice)/breakPrice*100
                );
                if (breakPrice < tomorrowInfo.getOpen()) {
                    successCount++;
                } else {
                    failCount++;
                }
//                if (tomorrowInfo.getChangeRatio()>0) {
//                    successCount++;
//                } else {
//                    failCount++;
//                }
            }
        }
        log.info("success count:{},fail count:{}", successCount, failCount);
    }
}
